package melon.saber.core.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.BeanUtils;
import org.junit.Assert;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;

/**
 * 反射工具
 *
 */
@SuppressWarnings("unchecked")
public abstract class ReflectUtil {

	/**
	 * 将Bean对象转化成Map对象
	 * @param obj
	 * @return
	 */
	public final static Map<String, Object> translateMap(final Object obj){
		Assert.assertNotNull("obj不能为空", obj);
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		Class<?> targetClass = AopUtils.getTargetClass(obj);
		ReflectionUtils.doWithFields(targetClass, new FieldCallback() {
			
			@Override
			public void doWith(Field field) throws IllegalArgumentException,
			IllegalAccessException {
				if(Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())){
					return;
				}
				field.setAccessible(true);
				resultMap.put(field.getName(), field.get(obj));
				field.setAccessible(false);
			}
		});
		return resultMap;
	}
	
	/**
	 * 将Bean对象转化成Map对象，并且可以指定属性名数组来生成
	 * @param obj Bean对象
	 * @param fieldNames 属性名字数组
	 * @return
	 */
	public final static Map<String, Object> translateMap(Object obj, String[] fieldNames){
		Assert.assertNotNull("obj不能为空", obj);
		final Map<String, Object> resultMap = new HashMap<String, Object>();
		Class<?> targetClass = obj.getClass();
		try{
			for(String fieldName : fieldNames){
				Field field = targetClass.getDeclaredField(fieldName);
				field.setAccessible(true);
				resultMap.put(field.getName(), field.get(obj));
				field.setAccessible(false);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return resultMap;
	}
	
	/**
	 * 将Map对象封装成Bean对象
	 * @param map 
	 * @param clazz 目标Bean的Class，目标Bean必须声明成公开类型
	 * @return
	 */
	public final static <T> T translateBean(Map<String, ?> map, Class<T> clazz){
		Assert.assertTrue("map和clazz不能为空", !CollectionUtils.isEmpty(map) && clazz != null);
		T obj = null;
		if(!checkIsPublic(clazz)){
			throw new IllegalArgumentException("类级别必须是公开的");
		}
		try {
			obj = newInstance(clazz);
			translateBean(map, obj);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	/**
	 * 取Map中的值覆盖Bean的属性值
	 * @param <T>
	 * @param map
	 * @param bean
	 * @return
	 */
	public final static <T> T mergePropertyBean(Map<?, ?> map, T bean){
		Assert.assertTrue("map和bean不能为空", bean != null && map != null);
		try {
			Iterator<?> iter = map.entrySet().iterator();
			Class<?> clazz = bean.getClass();
			while(iter.hasNext()){
				Entry<?,?> entry = (Entry<?,?>) iter.next();
				Field f = clazz.getDeclaredField((String)entry.getKey());
				if(f != null){
					f.setAccessible(true);
					f.set(bean, entry.getValue());
					f.setAccessible(false);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bean;
	}
	
	protected final static void translateBean(Map<String, ?> map, Object obj) throws IllegalAccessException, InvocationTargetException{
//		Field[] fields = obj.getClass().getDeclaredFields();
//		for(Field field : fields){
//			if(Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())){
//				continue;
//			}
//			field.setAccessible(true);
//			field.set(obj, map.get(field.getName()));
//			field.setAccessible(false);
//		}
		BeanUtils.populate(obj, map);
	}
	
	/**
	 * 内部类的实例化
	 * @param clazz 内部类的类型
	 * @return
	 */
	public final static <T> T newInstanceInnerClass(Class<T> clazz){
		Assert.assertNotNull(clazz);
		T obj = null;
		try {
			Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
			constructor.setAccessible(true);
			obj = (T)constructor.newInstance(obj);
			constructor.setAccessible(false);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	public final static <T> T newInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException{
		Assert.assertNotNull(clazz);
		T obj = null;
		if(checkIsInnerClass(clazz)){ //内部类要做特殊处理
			obj = newInstanceInnerClass(clazz);
		}else{
			obj = clazz.newInstance();
		}
		return obj;
	}
	
//	/**
//	 * 拷贝对象
//	 * @param <T>
//	 * @param source
//	 * @return
//	 */
//	public static <T> T copy(T source){
//		try {
//			T target = (T) newInstance(source.getClass());
//			BeanUtils.copyProperties(target, source);
//			return target;
//		} catch (Exception e) {
//			throw new RuntimeException("copy object error!", e);
//		}
//	}
	
	/**
	 * function 拷贝对象（深度拷贝）
	 * @param source
	 * @return
	 */
	public static <T> T copy(T source) {
		ByteArrayOutputStream byteArrayOS = null;
		ObjectOutputStream outputStream = null;
		
		ByteArrayInputStream byteArrayIS = null;
		ObjectInputStream inputStream = null;
		
		try {
			byteArrayOS = new ByteArrayOutputStream();
			outputStream = new ObjectOutputStream(byteArrayOS);
			outputStream.writeObject(source);
			
			byteArrayIS = new ByteArrayInputStream(byteArrayOS.toByteArray());
			inputStream = new ObjectInputStream(byteArrayIS);
			T dest = (T) inputStream.readObject();
			return dest;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} finally {
			try {
				if (byteArrayIS != null) byteArrayIS.close();
				if (inputStream != null) inputStream.close();
				if (outputStream != null) outputStream.close();
				if (byteArrayOS != null) byteArrayOS.close();
			} catch (Exception e2) {
			}
		}
		return null;
	}
	
	/**
	 * 检测clazz是否属于内部类
	 * @param clazz
	 * @return
	 */
	protected static boolean checkIsInnerClass(Class<?> clazz){
		Assert.assertNotNull(clazz);
		return (clazz.getEnclosingClass() != null);
	}
	
	public static boolean checkIsPublic(Class<?> clazz){
		Assert.assertNotNull(clazz);
		return Modifier.isPublic(clazz.getModifiers());
	}
	
	public static boolean checkIsPublic(Field field){
		Assert.assertNotNull(field);
		return Modifier.isPublic(field.getModifiers());
	}
	
	public static boolean checkIsFinal(Field field) {
		Assert.assertNotNull(field);
		return Modifier.isFinal(field.getModifiers());
	}
	
	public static boolean checkIsPublic(Method method){
		Assert.assertNotNull(method);
		return Modifier.isPublic(method.getModifiers());
	}
	
}
